function addEvent(obj, evType, fn) {
  if (obj.addEventListener) {
    obj.addEventListener(evType, fn, false);
    return true;
  } else if (obj.attachEvent) {
    var r = obj.attachEvent('on' + evType, fn);
    return r;
  } else {
    return false;
  }
}

function cancelEvent(ev) {
  var ev = ev || window.event;
  if (ev.stopPropagation) {
    ev.stopPropagation();
    ev.preventDefault();
  } else {
    ev.cancelBubble = true;
    ev.returnValue = true;
  }
}

function getStyle(el, styleProp) {
  return el.currentStyle ? el.currentStyle[styleProp] : (window.getComputedStyle ? window.getComputedStyle(el, null).getPropertyValue(styleProp) : null);
}

function purgeChilds(el) {
  while (el.firstChild) el.removeChild(el.firstChild);
}

/* obtêm dimensão vertical da área renderizável */
function getViewportHeight() {
  return window.innerHeight ? window.innerHeight : document.body.clientHeight;
}

/* calcula quanto o documento pode escorrer na vertical */
function getScrollMaxY() {
  // document height
  if (window.innerHeight && window.scrollMaxY) {
    // Firefox
    yWithScroll = window.innerHeight + window.scrollMaxY;
  } else if (document.body.scrollHeight > document.body.offsetHeight) {
    // todos exceto Explorer Mac
    yWithScroll = document.body.scrollHeight;
  } else {
    // funciona no Explorer 6 Strict, Mozilla (não FF) and Safari
    yWithScroll = document.body.offsetHeight;
  }
  return yWithScroll - getViewportHeight();
}

function docIsScrollable() { return getScrollMaxY() >= getViewportHeight(); }

/* checa sobreposição vertical de 'element' em 'topElement' */
function isOverlapping(element, topElement) {
  return element.offsetTop <= topElement.offsetTop + topElement.clientHeight;
}

Array.prototype.append = function (x) {
  this.push(x);
  return this;
}

Array.prototype.cat = function (x) { return this.append(x).join(' ').trim(); }

Array.prototype.px = function () { return this.append('px').join(''); }

/* workaround para forçar largura mínima declarada no CSS, ignorada por alguns navegadores */
function chkMinWidth(el) {
  var mw = getStyle(el, 'min-width');
  if (mw && (parseInt(getStyle(el, 'width')) < parseInt(mw))) {
    el.style.width = mw;
  }
}

/* centraliza elemento em ambas direções modificando propriedades CSS */
function center(el) {
  el.style.position = 'fixed';
  el.style.left = '50%';
  var d = el.clientWidth >> 1;
  el.style.marginLeft = ['-', d].px();
  el.style.marginRight = [d].px();
  el.style.top = '50%';
  d = el.clientHeight >> 1;
  el.style.marginTop = ['-', d].px();
  el.style.marginBottom = [d].px();
}

function $(s) {
  if (s.search(/\W/) != -1) return document.querySelector(s);
  var el = document.getElementById(s);
  return el ? el : ((el = document.getElementsByName(s)[0]) ? el : document.getElementsByClassName(s)[0]);
}

/**
 * Objeto visando responsividade a eventos com a melhor performance possível
 * preservando escopo, ponteiro p/elemento alvo da resposta, c/todas funções
 * 'callback' engatilhadas p/pronta resposta sem testes, exceto p/escopo.
 *
 *             el Ponteiro p/elemento alvo da resposta ao evento.
 *       funktion Função 'callback' aplicacada ao elemento alvo.
 *     evFunktion Função 'callback' de eventos, opcional c/default 'null'
 *                somente declarada se usar o argumento seguinte.
 * playOnCreation Indicador de execução do método "callback" na criação do
 *                objeto, opcional c/default 'null', assegurando execução
 *                somente quando o valor for 'true'.
 *
 * O método 'callback' a declarar como 'listener' de eventos se denomina 'play'
 * aplicando a função 'callback' de eventos e depois a função 'callback' do
 * elemento alvo.
*/
function Player(el, funktion, evFunktion, playOnCreation) {
  var scope = this;
  this.element = el;
  this.aktion = funktion;
  if (evFunktion) {
    this.evAktion = evFunktion;
    this.play = function wrapper() {
      if (this != scope) return wrapper.apply(scope, arguments);
      this.evAktion.apply(scope, arguments);
      this.aktion.apply(scope, [this.element]);
    };
  } else {
    this.play = function wrapper() {
      if (this != scope) return wrapper.apply(scope, arguments);
      this.aktion.apply(scope, [this.element]);
    };
  }
  if (playOnCreation === true) this.play();
}

function start() {

  /* altera a funcionalidade do botão de 'reset' para 'clear' */
  var elm = $("#header form fieldset:last-child input[type='button']");
  if (elm)
    addEvent(elm, 'click',
      new Player(
        elm.parentNode.parentNode,
        function (form) {
          form.YEAR_MONTH.selectedIndex = 0;
          form.USER_NAME.value = '*';
        }
      ).play);

  /* cancela o direcionamento do elemento âncora */
  elm = $('#footer a.rollover');
  addEvent(elm, 'click',
    new Player(
      elm,
      function (anchor) {
        anchor.blur();
        window.alert(anchor.title);
      },
      cancelEvent
    ).play);

  /* preenche o seletor de MÊS_ANO criando suas opções */
  if (typeof(OPTIONS) != 'undefined')
  {
    elm = $('#header form fieldset:first-child select');
    if (OPTIONS.length) {
      purgeChilds(elm);
      for (var j=0; j < OPTIONS.length; j++) {
        var option = document.createElement('option');
        option.value = OPTIONS[j].valor;
        option.innerHTML = OPTIONS[j].texto;
        elm.appendChild(option);
        if (OPTIONS[j].selecionado) elm.selectedIndex = j;
      }
    }
  }

  /* altera a disposição inicial do elemento 'header' de 'none' para 'block' */
  var HEADER = $('header');
  if (HEADER) HEADER.style.display = 'block';

  /* centraliza elemento da classe 'notitication' em ambas direções */
  elm = $('#conteudo.notification');
  if (elm) addEvent(window, 'resize',
    new Player(
      elm,
      function (el) {
        chkMinWidth(el);
        center(el);
        /* workaround p/evitar sobreposição de elementos */
        var header = $('header');
        if (header && isOverlapping(el, header)) {
          /* retorna a estático */
          el.style.position = 'static';
          el.style.left = el.style.top = 'auto';
          /* autocentralização horizontal */
          el.style.marginLeft = el.style.marginRight = 'auto';
          /* estabelece as margens verticais */
          if (getStyle(header, 'position') == 'fixed') {
            el.style.marginTop = [ header.clientHeight + 20 ].px();
            el.style.marginBottom = '0';
          } else {
            el.style.marginTop = '0';
            var footer = $('footer');
            if (isOverlapping(footer, el) && !docIsScrollable())
            {
              el.style.marginBottom = [ footer.clientHeight + 15 ].px();
            } else {
              el.style.marginBottom = '0';
            }
          }
        }
      },
      null,
      true).play);

  /* fixa o elemento 'footer' no rodapé */
  var FOOTER = $('footer');
  if (getStyle(FOOTER, 'position') != 'fixed')
  {
    var CONTEUDO = $('conteudo');
    if (isOverlapping(FOOTER, CONTEUDO) && !docIsScrollable())
    {
      FOOTER.className = FOOTER.className.split(' ').cat('rodape');
      CONTEUDO.style.marginBottom = [ FOOTER.clientHeight + 15 ].px();
    }
  }

  /* remove o elemento 'warning' e purga seus descendentes */
  if (HEADER && (elm = $('warning'))) {
    purgeChilds(elm);
    elm.parentNode.removeChild(elm); // remove o spinner
  }
}

addEvent(window, 'load', start);
